//**********  pngwriter.h   **********************************************
//  Author:                    Paul Blackburn
//
//  Email:                     individual61@users.sourceforge.net
//
//  Version:                   0.5.4   (19 / II / 2009)
//
//  Description:               Library that allows plotting a 48 bit
//                             PNG image pixel by pixel, which can 
//                             then be opened with a graphics program.
//  
//  License:                   GNU General Public License
//                             Copyright 2002, 2003, 2004, 2005, 2006, 2007,
//                             2008, 2009 Paul Blackburn
//                             
//  Website: Main:             http://pngwriter.sourceforge.net/
//           Sourceforge.net:  http://sourceforge.net/projects/pngwriter/
//           Freshmeat.net:    http://freshmeat.net/projects/pngwriter/
//           
//  Documentation:             This header file is commented, but for a
//                             quick reference document, and support,
//                             take a look at the website.
//
//*************************************************************************


/*
 *     This program is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License as
 *     published by the Free Software Foundation; either version 2 of
 *     the License, or (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public
 *     License along with this program; if not, write to the Free
 *     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *     MA 02111-1307 USA
 * 
 */

#ifndef PNGWRITER_H
#define PNGWRITER_H 1

#define PNGWRITER_VERSION 0.54

#include <png.h>

// REMEMBER TO ADD -DNO_FREETYPE TO YOUR COMPILATION FLAGS IF PNGwriter WAS
// COMPILED WITHOUT FREETYPE SUPPORT!!!
// 
// RECUERDA AGREGAR -DNO_FREETYPE A TUS OPCIONES DE COMPILACION SI PNGwriter  
// FUE COMPILADO SIN SOPORTE PARA FREETYPE!!!
// 
#ifndef NO_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#endif

#ifdef OLD_CPP // For compatibility with older compilers.
#include <iostream.h>
#include <math.h>
#include <wchar.h>
#include <string.h>
using namespace std;
#endif // from ifdef OLD_CPP

#ifndef OLD_CPP // Default situation.
#include <iostream>
#include <cmath>
#include <cwchar>
#include <string>
#endif // from ifndef OLD_CPP

//png.h must be included before FreeType headers.
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>

#define PNG_BYTES_TO_CHECK (4)
#define PNGWRITER_DEFAULT_COMPRESSION (6)

/**
 * Template that allows to get the difference between any kind of
 * numbers. Note that unsigned types can be compared, and if the
 * difference has to be added to some variable, the same_sign field
 * knows if the difference has to be added or subtracted.
 */
template< typename TYPE >
TYPE difference( const TYPE& a, const TYPE& b, bool& same_sign )
{
  same_sign = ( a > b );
  return same_sign ? a - b : b - a;
}

/**
 * Class that provides a wrapper aroud the basic png function,
 * allowing to use simple commands to create, edit and read a png
 * image.
 *
 * @author Paul Blackburn
 *
 * @date 19 / II / 2009
 */
class pngwriter 
{
 private:

  /*
   * Shortcut for unsigned char type.
   */
  typedef unsigned char Byte;
   
  char * filename_;
  char * textauthor_;
  char * textdescription_;
  char * texttitle_;
  char * textsoftware_;
   
  unsigned height_;
  unsigned width_;
  int backgroundcolour_;
  int bit_depth_;
  int rowbytes_;
  int colortype_;
  int compressionlevel_;
  bool transformation_; // Required by Mikkel's patch
   
  Byte * * graph_;
  double filegamma_;
  double screengamma_;
  static const double pi_;

  /*
   * "Master" methods : they can handle any opacity values. If the
   * opacity is more than .9999999, it will be rounded to 1 and only
   * the new colour will be used.
   * The usual methods are still there, and are used as interface, but
   * all the code is in the master methods now, which allows to have
   * one place where the code has to be changed instead of two (there
   * was always one normal version and a blend one).
   * In principle the int version is always used as the "reference",
   * the only exception is the plotCMYK one, for which the handling is
   * easier with doubles.
   */
  void master_circle_aux(const unsigned & xcentre, const unsigned & ycentre,
			 const unsigned & x, const unsigned & y,
			 const int & red, const int & green, const int & blue,
			 const double & opacity = 1.);
  void master_flood_fill_internal(const unsigned & xstart,
				  const unsigned & ystart,
				  const int & start_red,
				  const int & start_green,
				  const int & start_blue,
				  const int & fill_red,
				  const int & fill_green,
				  const int & fill_blue,
				  const double & opacity = 1. );
  void master_drawtop(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3,
		      const int & red, const int & green, const int & blue,
		      const double & opacity = 1. );
  void master_drawbottom(const unsigned & x1, const unsigned & y1,
			 const unsigned & x2, const unsigned & x3,
			 const unsigned & y3,
			 const int & red, const int & green, const int & blue,
			 const double & opacity = 1. );
  void master_line(const unsigned & xfrom, const unsigned & yfrom,
		   const unsigned & xto, const unsigned & yto,
		   const int & red, const int & green, const int & blue,
		   const double & opacity = 1. );
  void master_triangle(const unsigned & x1, const unsigned & y1,
		       const unsigned & x2, const unsigned & y2,
		       const unsigned & x3, const unsigned & y3,
		       const int & red, const int & green, const int & blue,
		       const double & opacity = 1. );
  void master_square(const unsigned & xfrom, const unsigned & yfrom,
		     const unsigned & xto, const unsigned & yto,
		     const int & red, const int & green,const int &  blue,
		     const double & opacity = 1.);
  void master_filledsquare(const unsigned & xfrom, const unsigned & yfrom,
			   const unsigned & xto, const unsigned & yto,
			   const int & red, const int & green, const int & blue,
			   const double & opacity = 1. );
  void master_circle(const unsigned & xcentre, const unsigned & ycentre,
		     const unsigned & radius,
		     const int & red, const int & green, const int & blue,
		     const double & opacity = 1.);
  void master_filledcircle(const unsigned & xcentre, const unsigned & ycentre,
			   const unsigned & radius,
			   const int & red, const int & green,
			   const int & blue, const double & opacity = 1. );
  void master_bezier( const int & startPtX, const int & startPtY,
		      const int & startControlX, const int & startControlY,
		      const int & endPtX, const int & endPtY,
		      const int & endControlX, const int & endControlY,
		      const int & red, const int & green, const int & blue,
		      const double & opacity = 1. );
  void master_plot_text(char * face_path, const int & fontsize,
			const unsigned & x_start, const unsigned & y_start,
			const double & angle, char * text,
			const int & red, const int & green, const int & blue,
			const double & opacity = 1. );
  void master_plot_text_utf8(char * face_path, const int & fontsize,
			     const unsigned & x_start,
			     const unsigned & y_start, const double & angle,
			     char * text, const int & red, const int & green,
			     const int & blue, const double & opacity = 1. );
  void master_boundary_fill(const unsigned & xstart, const unsigned & ystart,
			    const int &  boundary_red,
			    const int & boundary_green,
			    const int & boundary_blue,
			    const int & fill_red, const int & fill_green,
			    const int & fill_blue,
			    const double & opacity = 1. );
  void master_flood_fill(const unsigned & xstart, const unsigned & ystart,
			 const int & fill_red, const int & fill_green,
			 const int & fill_blue, const double & opacity = 1.);
  void master_polygon(unsigned * points, const unsigned & number_of_points,
		      const int & red, const int & green, const int & blue,
		      const double & opacity = 1. );
  void master_plotCMYK(const unsigned & x, const unsigned & y,
		       const double & cyan, const double & magenta,
		       const double & yellow, const double & black,
		       const double & opacity = 1. );
  void master_filledtriangle(const unsigned & x1, const unsigned & y1,
			     const unsigned & x2, const unsigned & y2,
			     const unsigned & x3, const unsigned & y3,
			     const int & red, const int & green,
			     const int & blue, const double & opacity = 1. );


  void circle_aux(const unsigned & xcentre, const unsigned & ycentre,
		  const unsigned & x, const unsigned & y,
		  const int & red, const int & green, const int & blue);
  void circle_aux_blend(const unsigned & xcentre, const unsigned & ycentre,
			const unsigned & x, const unsigned & y,
			const double & opacity,
			const int & red, const int & green, const int & blue);
  int check_if_png(char *file_name, FILE **fp);
  int read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr);
  int read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr,
		     png_bytepp *image, png_uint_32 *width,
		     png_uint_32 *height);
  void flood_fill_internal(const unsigned & xstart, const unsigned & ystart,
			   const int & start_red,
			   const int & start_green,
			   const int & start_blue,
			   const int & fill_red,
			   const int & fill_green,
			   const int & fill_blue);
  void flood_fill_internal_blend(const unsigned & xstart,
				 const unsigned & ystart,
				 const double & opacity,
				 const double & start_red,
				 const double & start_green,
				 const double & start_blue,
				 const double & fill_red,
				 const double & fill_green,
				 const double & fill_blue);

#ifndef NO_FREETYPE

  void master_my_draw_bitmap( FT_Bitmap * bitmap,
			      const unsigned & x, const unsigned & y,
			      const double & red,
			      const double & green,
			      const double & blue,
			      const double & opacity = 1. );
  void my_draw_bitmap( FT_Bitmap * bitmap,
		       const unsigned & x, const unsigned & y,
		       const double & red,
		       const double & green,
		       const double & blue);
  void my_draw_bitmap_blend( FT_Bitmap * bitmap,
			     const unsigned & x, const unsigned & y,
			     const double & opacity,
			     const double & red,
			     const double & green,
			     const double & blue);

#endif
   
  /* The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
   * which is a page that belongs to Nan C. Schaller, though
   * these algorithms appear to be the work of Eugene Vishnevsky. 
   * */
  void HSVtoRGB( double &r, double &g, double &b,
		 const double & h, const double & s, const double & v );
  void RGBtoHSV( const double & r, const double & g,
		 const double & b, double &h, double &s, double &v );

  /* drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
   * ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
   * */
  void drawtop(const unsigned & x1, const unsigned & y1, const unsigned & x2,
	       const unsigned & y2, const unsigned & x3,
	       const int & red, const int & green, const int & blue);
  void drawbottom(const unsigned & x1, const unsigned & y1, const unsigned & x2,
		  const unsigned & x3, const unsigned & y3,
		  const int & red, const int & green, const int & blue);
  void drawbottom_blend(const unsigned & x1, const unsigned & y1,
			const unsigned & x2, const unsigned & x3,
			const unsigned & y3, const double & opacity,
			const int & red, const int & green, const int & blue);
  void drawtop_blend(const unsigned & x1, const unsigned & y1,
		     const unsigned & x2, const unsigned & y2,
		     const unsigned & x3, const double & opacity,
		     const int & red, const int & green, const int & blue);

  int init_pixel_matrix();
  int init_pixel_matrix(Byte **source);

  void setbitdepth(const int & depth);
   
 public:

  /*
   * Collections that contains the colous indices.
   */
  enum RGBColours  { tRed, tGreen, tBlue };
  enum HSVColours  { tHue, tSaturation, tValue };
  enum CMYKColours { tCyan, tMagenta, tYellow, tBlack };

  /* General Notes
   * It is important to remember that all functions that accept an
   * argument of type "const char *" will also accept "char *", this
   * is done so you can have a changing filename (to make many PNG
   * images in series with a different name, for example), and to
   * allow you to use string type objects which can be easily turned
   * into const char * (if theString is an object of type string,
   * then it can be used as a const char * by saying
   * theString.c_str()).  It is also important to remember that
   * whenever a function has a colour coeffiecient as its argument,
   * that argument can be either an int from 0 to 65535 or a double
   * from 0.0 to 1.0.  It is important to make sure that you are
   * calling the function with the type that you want.  Remember that
   * 1 is an int, while 1.0 is a double, and will thus determine what
   * version of the function will be used. Similarly, do not make the
   * mistake of calling for example plot(x, y, 0.0, 0.0, 65535),
   * because there is no plot(int, int, double, double, int).  Also,
   * please note that plot() and read() (and the functions that use
   * them internally) are protected against entering, for example, a
   * colour coefficient that is over 65535 or over 1.0. Similarly,
   * they are protected against negative coefficients. read() will
   * return 0 when called outside the image range. This is actually
   * useful as zero-padding should you need it. */

  /* Compilation
   * A typical compilation would look like this:
   * 
   * g++ my_program.cc -o my_program freetype-config --cflags \
   * -I/usr/local/include -L/usr/local/lib -lpng -lpngwriter -lz \
   * -lfreetype
   * 
   * If you did not compile PNGwriter with FreeType support, then
   * remove the FreeType-related flags and add -DNO_FREETYPE
   * above.
   */
   
  /* Constructor
   * The constructor requires the width and the height of the image,
   * the background colour for the image and the filename of the file
   * (a pointer or simple "myfile.png"). The background colour can
   * only be initialized to a shade of grey (once the object has been
   * created you can do whatever you want, though), because generally
   * one wants either a white (65535 or 1.0) or a black (0 or 0.0)
   * background to start with.  The default constructor creates a
   * PNGwriter instance that is 250x250, white background, and
   * filename "out.png".
   *
   * Tip: The filename can be given as easily as: pngwriter
   * mypng(300, 300, 0.0, "myfile.png");
   *
   * Tip: If you are going to create a PNGwriter instance for reading
   * in a file that already exists, then width and height can be 1
   * pixel, and the size will be automatically adjusted once you use
   * readfromfile(). */
  pngwriter();
  pngwriter(const pngwriter &rhs);
  pngwriter(const unsigned & width, const unsigned & height,
	    const Byte & backgroundcolour,
	    char * filename, const int & depth = 16);
  pngwriter(const unsigned & width, const unsigned & height,
	    const int & backgroundcolour,
	    char * filename, const int & depth = 16);
  pngwriter(const unsigned & width, const unsigned & height,
	    const double & backgroundcolour,
	    char * filename, const int & depth = 16);
  pngwriter(const unsigned & width, const unsigned & height,
	    const Byte & backgroundcolour,
	    const char * filename, const int & depth = 16);
  pngwriter(const unsigned & width, const unsigned & height,
	    const int & backgroundcolour, const char * filename,
	    const int & depth = 16);
  pngwriter(const unsigned & width, const unsigned & height,
	    const double & backgroundcolour, const char * filename,
	    const int & depth = 16);

  /* Destructor
   * */
  ~pngwriter();

  /* Assignment Operator
   * */
  pngwriter & operator = (const pngwriter & rhs);
      
  /*  Plot
   * With this function a pixel at coordinates (x, y) can be set to
   * the desired colour.  The pixels are numbered starting from (1,
   * 1) and go to (width, height).  As with most functions in
   * PNGwriter, it has been overloaded to accept either int arguments
   * for the colour coefficients, or those of type double. If they
   * are of type int, they go from 0 to 65535. If they are of type
   * double, they go from 0.0 to 1.0.
   *
   * Tip: To plot using red, then specify plot(x, y, 1.0, 0.0,
   * 0.0). To make pink, just add a constant value to all three
   * coefficients, like this: plot(x, y, 1.0, 0.4, 0.4).
   *
   * Tip: If nothing is being plotted to your PNG file, make sure
   * that you remember to close() the instance before your program is
   * finished, and that the x and y position is actually within the
   * bounds of your image. If either is not, then PNGwriter will not
   * complain-- it is up to you to check for this!
   *
   * Tip: If you try to plot with a colour coefficient out of range,
   * a maximum or minimum coefficient will be assumed, according to
   * the given coefficient. For example, attempting to plot plot(x,
   * y, 1.0,-0.2,3.7) will set the green coefficient to 0 and the red
   * coefficient to 1.0. 
   */
  void  plot(const unsigned & x, const unsigned & y,
	     const Byte & red, const Byte  & green, const Byte & blue); 
  void  plot(const unsigned & x, const unsigned & y,
	     const int & red, const int & green, const int & blue); 
  void  plot(const unsigned & x, const unsigned & y,
	     const double & red, const double & green, const double & blue); 
                                                          
  /* Plot HSV
   * With this function a pixel at coordinates (x, y) can be set to
   * the desired colour, but with the colour coefficients given in
   * the Hue, Saturation, Value colourspace.  This has the advantage
   * that one can determine the colour that will be plotted with only
   * one parameter, the Hue. The colour coefficients must go from 0
   * to 65535 and be of type int, or be of type double and go from
   * 0.0 to 1.0.
   *
   */
  void plotHSV(const unsigned & x, const unsigned & y, const Byte & hue,
	       const Byte & saturation, const Byte & value);
  void plotHSV(const unsigned & x, const unsigned & y, const double & hue,
	       const double & saturation, const double & value);
  void plotHSV(const unsigned & x, const unsigned & y,
	       const int & hue, const int & saturation, const int & value); 

  /* Read
   * With this function we find out what colour the pixel (x, y)
   * is. If "colour" is 1, it will return the red coefficient, if it
   * is set to 2, the green one, and if it set to 3, the blue colour
   * coefficient will be returned, and this returned value will be of
   * type int and be between 0 and 65535.  Note that if you call
   * read() on a pixel outside the image range, the value returned
   * will be 0.
   */
  int read(const unsigned & x, const unsigned & y,
	   const RGBColours & colour);

  /* Read, Average
   * Same as the above, only that the average of the three colour
   * coefficients is returned.
   */
  int read(const unsigned & x, const unsigned & y);

  /* cRead
   * With this function we find out what colour the pixel (x, y)
   * is. If "colour" is 1, it will return the red coefficient, if it
   * is set to 2, the green one, and if it set to 3, the blue colour
   * coefficient will be returned, and this returned value will be of
   * type Byte and be between 0 and 255.  Note that if you
   * call read() on a pixel outside the image range, the value
   * returned will be 0.
   */
  Byte cread(const unsigned & x, const unsigned & y,
		      const RGBColours & colour);

  /* Read, Average
   * Same as the above, only that the average of the three colour
   * coefficients is returned.
   */
  Byte cread(const unsigned & x, const unsigned & y);
   
  /* dRead
   * With this function we find out what colour the pixel (x, y)
   * is. If "colour" is 1, it will return the red coefficient, if it
   * is set to 2, the green one, and if it set to 3, the blue colour
   * coefficient will be returned, and this returned value will be of
   * type double and be between 0.0 and 1.0.  Note that if you call
   * dread() outside the image range, the value returned will be
   * 0.0 
   */
  double dread(const unsigned & x, const unsigned & y,
	       const RGBColours & colour);
   
  /* dRead, Average
   * Same as the above, only that the average of the three colour
   * coefficients is returned.
   */
  double dread(const unsigned & x, const unsigned & y);             
   
  /* Read HSV
   * With this function we find out what colour the pixel (x, y) is,
   * but in the Hue, Saturation, Value colourspace. If "colour" is 1,
   * it will return the Hue coefficient, if it is set to 2, the
   * Saturation one, and if it set to 3, the Value colour coefficient
   * will be returned, and this returned value will be of type int
   * and be between 0 and 65535. Important: If you attempt to read
   * the Hue of a pixel that is a shade of grey, the value returned
   * will be nonsensical or even NaN. This is just the way the RGB ->
   * HSV algorithm works: the Hue of grey is not defined. You might
   * want to check whether the pixel you are reading is grey before
   * attempting a readHSV().
   *
   * Tip: This is especially useful for categorizing sections of the
   * image according to their colour.
   */
  int readHSV(const unsigned & x, const unsigned & y,
	      const HSVColours & colour);
   
  /* cRead HSV
   * With this function we find out what colour the pixel (x, y) is,
   * but in the Hue, Saturation, Value colourspace. If "colour" is 1,
   * it will return the Hue coefficient, if it is set to 2, the
   * Saturation one, and if it set to 3, the Value colour coefficient
   * will be returned, and this returned value will be of type
   * unsigned chat and be between 0 and 255. Important: If you
   * attempt to read the Hue of a pixel that is a shade of grey, the
   * value returned will be nonsensical or even NaN. This is just the
   * way the RGB -> HSV algorithm works: the Hue of grey is not
   * defined. You might want to check whether the pixel you are
   * reading is grey before attempting a creadHSV().
   *
   * Tip: This is especially useful for categorizing sections of the
   * image according to their colour.
   */
  Byte creadHSV(const unsigned & x, const unsigned & y,
		const HSVColours & colour);
    
  /* dRead HSV
   * With this function we find out what colour the pixel (x, y) is,
   * but in the Hue, Saturation, Value colourspace. If "colour" is 1,
   * it will return the Hue coefficient, if it is set to 2, the
   * Saturation one, and if it set to 3, the Value colour coefficient
   * will be returned, and this returned value will be of type double
   * and be between 0.0 and 1.0. 
   */
  double dreadHSV(const unsigned & x, const unsigned & y,
		  const HSVColours & colour);
   
  /* Clear
   * The whole image is set to black.
   * */ 
  void clear(void);    
   
  /* Close
   * Close the instance of the class, and write the image to disk.
   * Tip: If you do not call this function before your program ends,
   * no image will be written to disk. */
  void close(void); 

  /* Rename
   * To rename the file once an instance of pngwriter has been
   * created.  Useful for assigning names to files based upon their
   * content.
   *
   * Tip: This is as easy as calling pngwriter_rename("newname.png")
   * If the argument is a long unsigned, for example 77, the
   * filename will be changed to 0000000077.png
   *
   * Tip: Use this to create sequences of images for movie
   * generation.
   */
  void pngwriter_rename(char * newname);               
  void pngwriter_rename(const char * newname);            
  void pngwriter_rename(const long unsigned & index);            

  /* Figures
   * These functions draw basic shapes. Available in both int and
   * double versions.  The line functions use the fast Bresenham
   * algorithm. Despite the name, the square functions draw
   * rectangles. The circle functions use a fast integer math
   * algorithm. The filled circle functions make use of sqrt().
   */
  void line(const unsigned & xfrom, const unsigned & yfrom,
	    const unsigned & xto, const unsigned & yto,
	    const int & red, const int & green,const int &  blue);
  void line(const unsigned & xfrom, const unsigned & yfrom,
	    const unsigned & xto, const unsigned & yto,
	    const Byte & red, const Byte & green, const Byte & blue);
  void line(const unsigned & xfrom, const unsigned & yfrom,
	    const unsigned & xto, const unsigned & yto,
	    const double & red, const double & green, const double & blue);
  
  void triangle(const unsigned & x1, const unsigned & y1,
		const unsigned & x2, const unsigned & y2,
		const unsigned & x3, const unsigned & y3,
		const int & red, const int & green, const int & blue);
  void triangle(const unsigned & x1, const unsigned & y1,
		const unsigned & x2, const unsigned & y2,
		const unsigned & x3, const unsigned & y3,
		const Byte & red, const Byte & green,const Byte & blue);
  void triangle(const unsigned & x1, const unsigned & y1,
		const unsigned & x2, const unsigned & y2,
		const unsigned & x3, const unsigned & y3,
		const double & red, const double & green, const double & blue);
  void triangle_blend(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3, const unsigned & y3,
		      const double & opacity,
		      const int & red, const int & green, const int & blue);
  void triangle_blend(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3, const unsigned & y3,
		      const double & opacity,
		      const Byte & red, const Byte & green,const Byte & blue);
  void triangle_blend(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3, const unsigned & y3,
		      const double & opacity,
		      const double & red, const double & green,
		      const double & blue);
   
  void square(const unsigned & xfrom, const unsigned & yfrom,
	      const unsigned & xto, const unsigned & yto,
	      const int & red, const int & green,const int &  blue);
  void square(const unsigned & xfrom, const unsigned & yfrom,
	      const unsigned & xto, const unsigned & yto,
	      const Byte & red, const Byte & green,const Byte & blue);
  void square(const unsigned & xfrom, const unsigned & yfrom,
	      const unsigned & xto, const unsigned & yto,
	      const double & red, const double & green, const double & blue);
   
  void filledsquare(const unsigned & xfrom, const unsigned & yfrom,
		    const unsigned & xto, const unsigned & yto,
		    const int & red, const int & green,const int & blue);
  void filledsquare(const unsigned & xfrom, const unsigned & yfrom,
		    const unsigned & xto, const unsigned & yto,
		    const Byte & red, const Byte & green,const Byte & blue);
  void filledsquare(const unsigned & xfrom, const unsigned & yfrom,
		    const unsigned & xto, const unsigned & yto,
		    const double & red, const double & green,
		    const double & blue);

  void circle(const unsigned & xcentre, const unsigned & ycentre,
	      const unsigned & radius,
	      const int & red, const int & green, const int & blue);
  void circle(const unsigned & xcentre, const unsigned & ycentre,
	      const unsigned & radius,
	      const Byte & red, const Byte & green,const Byte & blue);
  void circle(const unsigned & xcentre, const unsigned & ycentre,
	      const unsigned & radius,
	      const double & red, const double & green, const double & blue);
  
  void filledcircle(const unsigned & xcentre, const unsigned & ycentre,
		    const unsigned & radius,
		    const int & red, const int & green, const int & blue);
  void filledcircle(const unsigned & xcentre, const unsigned & ycentre,
		    const unsigned & radius,
		    const Byte & red, const Byte & green,const Byte & blue);
  void filledcircle(const unsigned & xcentre, const unsigned & ycentre,
		    const unsigned & radius,
		    const double & red, const double & green,
		    const double & blue);
   
  /* Read From File
   * Open the existing PNG image, and copy it into this instance of
   * the class. It is important to mention that PNG variants are
   * supported. Very generally speaking, most PNG files can now be
   * read (as of version 0.5.4), but if they have an alpha channel it
   * will be completely stripped. If the PNG file uses GIF-style
   * transparency (where one colour is chosen to be transparent),
   * PNGwriter will not read the image properly, but will not
   * complain. Also, if any ancillary chunks are included in the PNG
   * file (chroma, filter, etc.), it will render with a slightly
   * different tonality. For the vast majority of PNGs, this should
   * not be an issue. Note: If you read an 8-bit PNG, the internal
   * representation of that instance of PNGwriter will be 8-bit (PNG
   * files of less than 8 bits will be upscaled to 8 bits). To
   * convert it to 16-bit, just loop over all pixels, reading them
   * into a new instance of PNGwriter. New instances of PNGwriter are
   * 16-bit by default.
   */

  void readfromfile(char * name);  
  void readfromfile(const char * name); 

  /* Get Height
   * When you open a PNG with readfromfile() you can find out its
   * height with this function.
   */
  const unsigned & getheight(void);
   
  /* Get Width
   * When you open a PNG with readfromfile() you can find out its
   * width with this function.
   */
  const unsigned & getwidth(void);

  /* Set Compression Level
   * Set the compression level that will be used for the image. -1 is
   * to use the default, 0 is none, 9 is best compression.
   *
   * Remember that this will affect how long it will take to close()
   * the image. A value of 2 or 3 is good enough for regular use, but
   * for storage or transmission you might want to take the time to
   * set it at 9.
   */
  void setcompressionlevel(const int & level);

  /* Get Bit Depth
   * When you open a PNG with readfromfile() you can find out its bit
   * depth with this function.  Mostly for troubleshooting uses.
   */
  const int & getbitdepth(void);
   
  /* Get Colour Type
   * When you open a PNG with readfromfile() you can find out its colour type (libpng categorizes 
   * different styles of image data with this number).
   * Mostly for troubleshooting uses.
   * */
  const int & getcolortype(void);
   
  /* Set Gamma Coeff
   * Set the image's gamma (file gamma) coefficient. This is
   * experimental, but use it if your image's colours seem too bright
   * or too dark. The default value of 0.5 should be fine. The
   * standard disclaimer about Mac and PC gamma settings applies.
   */
  void setgamma(const double & gamma);

   
  /* Get Gamma Coeff
   * Get the image's gamma coefficient. This is experimental.
   */
  const double & getgamma(void);

  /* Bezier Curve
   * (After Frenchman Pierre Bézier from Regie Renault) A collection
   * of formulae for describing curved lines and surfaces, first used
   * in 1972 to model automobile surfaces.  (from the The Free
   * On-line Dictionary of Computing) See
   * http://www.moshplant.com/direct-or/bezier/ for one of many
   * available descriptions of bezier curves.
   *
   * There are four points used to define the curve: the two
   * endpoints of the curve are called the anchor points, while the
   * other points, which define the actual curvature, are called
   * handles or control points.  Moving the handles lets you modify
   * the shape of the curve.
   */
     
  void bezier( const int & startPtX, const int & startPtY,
	       const int & startControlX, const int & startControlY,
	       const int & endPtX, const int & endPtY,
	       const int & endControlX, const int & endControlY,
	       const double & red, const double & green, const double & blue);
  void bezier( const int & startPtX, const int & startPtY,
	       const int & startControlX, const int & startControlY,
	       const int & endPtX, const int & endPtY,
	       const int & endControlX, const int & endControlY,
	       const Byte & red, const Byte & green, const Byte & blue);
  void bezier( const int & startPtX, const int & startPtY,
	       const int & startControlX, const int & startControlY,
	       const int & endPtX, const int & endPtY,
	       const int & endControlX, const int & endControlY,
	       const int & red, const int & green, const int & blue);

  /* Set Text
   * Sets the text information in the PNG header. If it is not
   * called, the default is used.
   */
  void settext(char * title, char * author, char * description,
	       char * software);
  void settext(const char * title, const char * author,
	       const char * description, const char * software);

  /* Version Number
   * Returns the PNGwriter version number.
   */
  static double version(void);

  /* Write PNG
   * Writes the PNG image to disk. You can still change the PNGwriter
   * instance after this.
   *
   * Tip: This is exactly the same as close(), but easier to
   * remember.
   *
   * Tip: To make a sequence of images using only one instance of
   * PNGwriter, alter the image, change its name, write_png(), then
   * alter the image, change its name, write_png(), etc.
   */
  void write_png(void);

  /* Plot Text
   * Uses the Freetype2 library to set text in the image. face_path
   * is the file path to a TrueType font file (.ttf) (FreeType2 can
   * also handle other types). fontsize specifices the approximate
   * height of the rendered font in pixels. x_start and y_start
   * specify the placement of the lower, left corner of the text
   * string. angle is the text angle in radians. text is the text to
   * be rendered.  The colour coordinates can be doubles from 0.0 to
   * 1.0 or ints from 0 to 65535.
   *
   * Tip: PNGwriter installs a few fonts in
   * /usr/local/share/pngwriter/fonts to get you started.
   *
   * Tip: Remember to add -DNO_FREETYPE to your compilation flags if
   * PNGwriter was compiled without FreeType support.
   */
  void plot_text(char * face_path, const int & fontsize,
		 const unsigned & x_start, const unsigned & y_start,
		 const double & angle, char * text,
		 const double & red, const double & green, const double & blue);
  void plot_text(char * face_path, const int & fontsize,
		 const unsigned & x_start, const unsigned & y_start,
		 const double & angle, char * text,
		 const Byte & red, const Byte & green, const Byte & blue);
  void plot_text(char * face_path, const int & fontsize,
		 const unsigned & x_start, const unsigned & y_start,
		 const double & angle, char * text,
		 const int & red, const int & green, const int & blue);

   
  /* Plot UTF-8 Text 
   * Same as the above, but the text to be plotted is encoded in
   * UTF-8. Why would you want this? To be able to plot all
   * characters available in a large TrueType font, for example: for
   * rendering Japenese, Chinese and other languages not restricted
   * to the standard 128 character ASCII space.
   *
   * Tip: The quickest way to get a string into UTF-8 is to write it
   * in an adequate text editor, and save it as a file in UTF-8
   * encoding, which can then be read in in binary mode.
   */
  void plot_text_utf8(char * face_path, const int & fontsize,
		      const unsigned & x_start, const unsigned & y_start,
		      const double & angle, char * text,
		      const double & red, const double & green,
		      const double & blue);
  void plot_text_utf8(char * face_path, const int & fontsize,
		      const unsigned & x_start, const unsigned & y_start,
		      const double & angle, char * text,
		      const Byte & red, const Byte & green, const Byte & blue);
  void plot_text_utf8(char * face_path, const int & fontsize,
		      const unsigned & x_start, const unsigned & y_start,
		      const double & angle, char * text,
		      const int & red, const int & green, const int & blue);

  /* Bilinear Interpolation of Image
   * Given a doubleing point coordinate (x from 0.0 to width, y from
   * 0.0 to height), this function will return the interpolated
   * colour intensity specified by colour (where red = 1, green = 2,
   * blue = 3).  bilinear_interpolate_read() returns an int from 0 to
   * 65535, and bilinear_interpolate_dread() returns a double from
   * 0.0 to 1.0.
   *
   * Tip: Especially useful for enlarging an image.
   */
  int bilinear_interpolation_read(const double & x, const double & y,
				  const RGBColours & colour);
  Byte bilinear_interpolation_cread(const double & x, const double & y,
				    const RGBColours & colour);
  double bilinear_interpolation_dread(const double & x, const double & y,
				      const RGBColours & colour);
   
  /* Plot Blend
   * Plots the colour given by red, green blue, but blended with the
   * existing pixel value at that position. opacity is a double that
   * goes from 0.0 to 1.0.  0.0 will not change the pixel at all, and
   * 1.0 will plot the given colour.  Anything in between will be a
   * blend of both pixel levels. Please note: This is neither alpha
   * channel nor PNG transparency chunk support. This merely blends
   * the plotted pixels.
   */
   
  void plot_blend(const unsigned & x, const unsigned & y,
		  const double & opacity,
		  const int & red, const int & green, const int & blue);
  void plot_blend(const unsigned & x, const unsigned & y,
		  const double & opacity,
		  const Byte & red, const Byte & green, const Byte & blue);
  void plot_blend(const unsigned & x, const unsigned & y,
		  const double & opacity, const double & red,
		  const double & green, const double & blue);
   
  /* Invert
   * Inverts the image in RGB colourspace.
   * */
  void invert(void);

  /* Resize Image
   * Resizes the PNGwriter instance. Note: All image data is set to
   * black (this is a resizing, not a scaling, of the image).
   */
  void resize(const int & width, const int & height);

  /* Boundary Fill
   * All pixels adjacent to the start pixel will be filled with the
   * fill colour, until the boundary colour is encountered.  For
   * example, calling boundary_fill() with the boundary colour set to
   * red, on a pixel somewhere inside a red circle, will fill the
   * entire circle with the desired fill colour. If, on the other
   * hand, the circle is not the boundary colour, the rest of the
   * image will be filled.  The colour components are either doubles
   * from 0.0 to 1.0 or ints from 0 to 65535.
   */
  void boundary_fill(const unsigned & xstart, const unsigned & ystart,
		     const double &  boundary_red,
		     const double & boundary_green,
		     const double & boundary_blue,
		     const double & fill_red, const double & fill_green,
		     const double & fill_blue);
  void boundary_fill(const unsigned & xstart, const unsigned & ystart,
		     const Byte &  boundary_red, const Byte & boundary_green,
		     const Byte & boundary_blue,
		     const Byte & fill_red, const Byte & fill_green,
		     const Byte & fill_blue);
  void boundary_fill(const unsigned & xstart, const unsigned & ystart,
		     const int & boundary_red, const int & boundary_green,
		     const int & boundary_blue,
		     const int & fill_red, const int & fill_green,
		     const int & fill_blue) ;

  /* Flood Fill
   * All pixels adjacent to the start pixel will be filled with the
   * fill colour, if they are the same colour as the start pixel. For
   * example, calling flood_fill() somewhere in the interior of a
   * solid blue rectangle will colour the entire rectangle the fill
   * colour. The colour components are either doubles from 0.0 to 1.0
   * or ints from 0 to 65535. */
  void flood_fill(const unsigned & xstart, const unsigned & ystart,
		  const double & fill_red, const double & fill_green,
		  const double & fill_blue) ;
  void flood_fill(const unsigned & xstart, const unsigned & ystart,
		  const Byte & fill_red, const Byte & fill_green,
		  const Byte & fill_blue) ;
  void flood_fill(const unsigned & xstart, const unsigned & ystart,
		  const int & fill_red, const int & fill_green,
		  const int & fill_blue) ;

  /* Polygon
   * This function takes an array of integer values containing the
   * coordinates of the vertexes of a polygon.  Note that if you want
   * a closed polygon, you must repeat the first point's coordinates
   * for the last point.  It also requires the number of points
   * contained in the array. For example, if you wish to plot a
   * triangle, the array will contain 6 elements, and the number of
   * points is 3. Be very careful about this; if you specify the
   * wrong number of points, your program will either segfault or
   * produce points at nonsensical coordinates.  The colour
   * components are either doubles from 0.0 to 1.0 or ints from 0 to
   * 65535.
   */
  void polygon(unsigned * points, const unsigned & number_of_points,
	       const double & red, const double & green, const double & blue);
  void polygon(unsigned * points, const unsigned & number_of_points,
	       const Byte & red, const Byte & green, const Byte & blue);
  void polygon(unsigned * points, const unsigned & number_of_points,
	       const int & red, const int & green, const int & blue);
     
  /* Plot CMYK
   * Plot a point in the Cyan, Magenta, Yellow, Black
   * colourspace. Please note that this colourspace is lossy, i.e. it
   * cannot reproduce all colours on screen that RGB can. The
   * difference, however, is barely noticeable. The algorithm used is
   * a standard one. The colour components are either doubles from
   * 0.0 to 1.0 or ints from 0 to 65535.
   */
  void plotCMYK(const unsigned & x, const unsigned & y,
		const double & cyan, const double & magenta,
		const double & yellow, const double & black);
  void plotCMYK(const unsigned & x, const unsigned & y,
		const Byte & cyan, const Byte & magenta,
		const Byte & yellow, const Byte & black);
  void plotCMYK(const unsigned & x, const unsigned & y,
		const int & cyan, const int & magenta,
		const int & yellow, const int & black);
   
  /* Read CMYK, Double version
   * Get a pixel in the Cyan, Magenta, Yellow, Black colourspace. if
   * 'colour' is 1, the Cyan component will be returned as a double
   * from 0.0 to 1.0. If 'colour is 2, the Magenta colour component
   * will be returned, and so on, up to 4.
   */
  double dreadCMYK(const unsigned & x, const unsigned & y,
		   const CMYKColours & colour);

  /* Read CMYK
   * Same as the above, but the colour components returned are an int
   * from 0 to 65535.
   */
  int readCMYK(const unsigned & x, const unsigned & y,
	       const CMYKColours & colour);

  /* Read CMYK
   * Same as the above, but the colour components returned are an int
   * from 0 to 255.
   */
  Byte creadCMYK(const unsigned & x, const unsigned & y,
			  const CMYKColours & colour);

  /* Scale Proportional
   * Scale the image using bilinear interpolation. If k is greater
   * than 1.0, the image will be enlarged.  If k is less than 1.0,
   * the image will be shrunk. Negative or null values of k are not
   * allowed.  The image will be resized and the previous content
   * will be replaced by the scaled image.
   *
   * Tip: use getheight() and getwidth() to find out the new width
   * and height of the scaled image.
   *
   * Note: After scaling, all images will have a bit depth of 16,
   * even if the original image had a bit depth of 8.
   */
  void scale_k(const double & k);
   
  /* Scale Non-Proportional
   * Scale the image using bilinear interpolation, with different
   * horizontal and vertical scale factors.
   */
  void scale_kxky(double kx, double ky);
   
  /* Scale To Target Width and Height
   * Scale the image in such a way as to meet the target width and
   * height.
   *
   * Tip: if you want to keep the image proportional, scale_k() might
   * be more appropriate.
   */
  void scale_wh(const int & finalwidth, const int & finalheight);


  /* Blended Functions
   * All these functions are identical to their non-blended
   * types. They take an extra argument, opacity, which is a double
   * from 0.0 to 1.0 and represents how much of the original pixel
   * value is retained when plotting the new pixel. In other words,
   * if opacity is 0.7, then after plotting, the new pixel will be
   * 30% of the original colour the pixel was, and 70% of the new
   * colour, whatever that may be. As usual, each function is
   * available in int or double versions.  Please note: This is
   * neither alpha channel nor PNG transparency chunk support. This
   * merely blends the plotted pixels.
   */
  
  // Start Blended Functions
  
  void plotHSV_blend(const unsigned & x, const unsigned & y,
		     const double & opacity, const double & hue,
		     const double & saturation, const double & value);
  void plotHSV_blend(const unsigned & x, const unsigned & y,
		     const double & opacity, const Byte & hue,
		     const Byte & saturation, const Byte & value);
  void plotHSV_blend(const unsigned & x, const unsigned & y,
		     const double & opacity, const int & hue,
		     const int & saturation, const int & value);

  void line_blend(const unsigned & xfrom, const unsigned & yfrom,
		  const unsigned & xto, const unsigned & yto,
		  const double & opacity, const int & red,
		  const int & green, const int &  blue);
  void line_blend(const unsigned & xfrom, const unsigned & yfrom,
		  const unsigned & xto, const unsigned & yto,
		  const double & opacity, const Byte & red,
		  const Byte & green, const Byte & blue);
  void line_blend(const unsigned & xfrom, const unsigned & yfrom,
		  const unsigned & xto, const unsigned & yto,
		  const double & opacity, const double & red,
		  const double & green, const double & blue);
  
  void square_blend(const unsigned & xfrom, const unsigned & yfrom,
		    const unsigned & xto, const unsigned & yto,
		    const double & opacity, const int & red,
		    const int & green,const int &  blue);
  void square_blend(const unsigned & xfrom, const unsigned & yfrom,
		    const unsigned & xto, const unsigned & yto,
		    const double & opacity, const Byte & red,
		    const Byte & green,const Byte & blue);
  void square_blend(const unsigned & xfrom, const unsigned & yfrom,
		    const unsigned & xto, const unsigned & yto,
		    const double & opacity, const double & red,
		    const double & green,const double & blue);
   
  void filledsquare_blend(const unsigned & xfrom, const unsigned & yfrom,
			  const unsigned & xto, const unsigned & yto,
			  const double & opacity, const int & red,
			  const int & green,const int &  blue);
  void filledsquare_blend(const unsigned & xfrom, const unsigned & yfrom,
			  const unsigned & xto, const unsigned & yto,
			  const double & opacity, const Byte & red,
			  const Byte & green,const Byte & blue);
  void filledsquare_blend(const unsigned & xfrom, const unsigned & yfrom,
			  const unsigned & xto, const unsigned & yto,
			  const double & opacity, const double & red,
			  const double & green,const double & blue);

  void circle_blend(const unsigned & xcentre, const unsigned & ycentre,
		    const unsigned & radius, const double & opacity,
		    const int & red, const int & green, const int & blue);
  void circle_blend(const unsigned & xcentre, const unsigned & ycentre,
		    const unsigned & radius, const double & opacity,
		    const Byte & red, const Byte & green, const Byte & blue);
  void circle_blend(const unsigned & xcentre, const unsigned & ycentre,
		    const unsigned & radius, const double & opacity,
		    const double & red, const double & green,
		    const double & blue);
   
  void filledcircle_blend(const unsigned & xcentre, const unsigned & ycentre,
			  const unsigned & radius, const double & opacity,
			  const int & red, const int & green, const int & blue);
  void filledcircle_blend(const unsigned & xcentre, const unsigned & ycentre,
			  const unsigned & radius, const double & opacity,
			  const Byte & red, const Byte & green,
			  const Byte & blue);
  void filledcircle_blend(const unsigned & xcentre, const unsigned & ycentre,
			  const unsigned & radius, const double & opacity,
			  const double & red, const double & green,
			  const double & blue);

  void bezier_blend( const int & startPtX, const int & startPtY,
		     const int & startControlX, const int & startControlY,
		     const int & endPtX, const int & endPtY,
		     const int & endControlX, const int & endControlY,
		     const double & opacity, const double & red,
		     const double & green, const double & blue);
  void bezier_blend( const int & startPtX, const int & startPtY,
		     const int & startControlX, const int & startControlY,
		     const int & endPtX, const int & endPtY,
		     const int & endControlX, const int & endControlY,
		     const double & opacity,
		     const Byte & red, const Byte & green, const Byte & blue);
   
  void bezier_blend( const int & startPtX, const int & startPtY,
		     const int & startControlX, const int & startControlY,
		     const int & endPtX, const int & endPtY,
		     const int & endControlX, const int & endControlY,
		     const double & opacity,
		     const int & red, const int & green, const int & blue);
   
  void plot_text_blend(char * face_path, const int & fontsize,
		       const unsigned & x_start, const unsigned & y_start,
		       const double & angle, char * text,
		       const double & opacity, const double & red,
		       const double & green, const double & blue);
  void plot_text_blend(char * face_path, const int & fontsize,
		       const unsigned & x_start, const unsigned & y_start,
		       const double & angle, char * text,
		       const double & opacity,
		       const Byte & red, const Byte & green, const Byte & blue);
  void plot_text_blend(char * face_path, const int & fontsize,
		       const unsigned & x_start, const unsigned & y_start,
		       const double & angle, char * text,
		       const double & opacity,
		       const int & red, const int & green, const int & blue);

  void plot_text_utf8_blend(char * face_path, const int & fontsize,
			    const unsigned & x_start, const unsigned & y_start,
			    const double & angle, char * text,
			    const double & opacity, const double & red,
			    const double & green, const double & blue);
  void plot_text_utf8_blend(char * face_path, const int & fontsize,
			    const unsigned & x_start, const unsigned & y_start,
			    const double & angle, char * text,
			    const double & opacity, const Byte & red,
			    const Byte & green, const Byte & blue);
  void plot_text_utf8_blend(char * face_path, const int & fontsize,
			    const unsigned & x_start, const unsigned & y_start,
			    const double & angle, char * text,
			    const double & opacity, const int & red,
			    const int & green, const int & blue);

  void boundary_fill_blend(const unsigned & xstart, const unsigned & ystart,
			   const double & opacity,
			   const double & boundary_red,
			   const double & boundary_green,
			   const double & boundary_blue,
			   const double & fill_red,
			   const double & fill_green,
			   const double & fill_blue);
  void boundary_fill_blend(const unsigned & xstart, const unsigned & ystart,
			   const double & opacity,
			   const Byte & boundary_red,
			   const Byte & boundary_green,
			   const Byte & boundary_blue,
			   const Byte & fill_red,
			   const Byte & fill_green,
			   const Byte & fill_blue);
  void boundary_fill_blend(const unsigned & xstart, const unsigned & ystart,
			   const double & opacity,
			   const int & boundary_red,
			   const int & boundary_green,
			   const int & boundary_blue,
			   const int & fill_red,
			   const int & fill_green,
			   const int & fill_blue) ;

  void flood_fill_blend(const unsigned & xstart, const unsigned & ystart,
			const double & opacity,
			const double & fill_red,
			const double & fill_green,
			const double & fill_blue) ;
  void flood_fill_blend(const unsigned & xstart, const unsigned & ystart,
			const double & opacity,
			const Byte & fill_red,
			const Byte & fill_green,
			const Byte & fill_blue) ;
  void flood_fill_blend(const unsigned & xstart, const unsigned & ystart,
			const double & opacity,
			const int & fill_red,
			const int & fill_green,
			const int & fill_blue) ;

  void polygon_blend(unsigned * points, const unsigned & number_of_points,
		     const double & opacity, const double & red,
		     const double & green, const double & blue);
  void polygon_blend(unsigned * points, const unsigned & number_of_points,
		     const double & opacity,
		     const Byte & red, const Byte & green, const Byte & blue);
  void polygon_blend(unsigned * points, const unsigned & number_of_points,
		     const double & opacity,
		     const int & red, const int & green, const int & blue);
     
  void plotCMYK_blend(const unsigned & x, const unsigned & y,
		      const double & opacity, const double & cyan,
		      const double & magenta, const double & yellow,
		      const double & black);
  void plotCMYK_blend(const unsigned & x, const unsigned & y,
		      const double & opacity, const Byte & cyan,
		      const Byte & magenta, const Byte & yellow,
		      const Byte & black);
  void plotCMYK_blend(const unsigned & x, const unsigned & y,
		      const double & opacity, const int & cyan,
		      const int & magenta, const int & yellow,
		      const int & black);

  // End of Blended Functions
  
  /* Laplacian
   * This function applies a discrete laplacian to the image,
   * multiplied by a constant factor.  The kernel used in this case
   * is:
   *                1.0  1.0  1.0
   *                1.0 -8.0  1.0
   *                1.0  1.0  1.0
   * Basically, this works as an edge detector. The current pixel is
   * assigned the sum of all neighbouring pixels, multiplied by the
   * corresponding kernel element. For example, imagine a pixel and
   * its 8 neighbours:
   *                1.0    1.0    0.0  0.0
   *                1.0  ->1.0<-  0.0  0.0
   *                1.0    1.0    0.0  0.0
   * This represents a border between white and black, black is on
   * the right. Applying the laplacian to the pixel specified above
   * pixel gives:
   *                1.0*1.0  + 1.0*1.0  + 0.0*1.0 +
   *                1.0*1.0  + 1.0*-8.0 + 0.0*1.0 +
   *                1.0*1.0  + 1.0*1.0  + 0.0*1.0   = -3.0
   * Applying this to the pixel to the right of the pixel considered
   * previously, we get a sum of 3.0.  That is, after passing over an
   * edge, we get a high value for the pixel adjacent to the
   * edge. Since PNGwriter limits the colour components if they are
   * off-scale, and the result of the laplacian may be negative, a
   * scale factor and an offset value are included. This might be
   * useful for keeping things within range or for bringing out more
   * detail in the edge detection. The final pixel value will be
   * given by:
   *   final value =  laplacian(original pixel)*k + offset
   *
   * Tip: Try a value of 1.0 for k to start with, and then experiment
   * with other values.
   */
  void laplacian(const double & k, const double & offset);

  /* Filled Triangle
   * Draws the triangle specified by the three pairs of points in the
   * colour specified by the colour coefficients. The colour
   * components are either doubles from 0.0 to 1.0 or ints from 0 to
   * 65535.
   */
  void filledtriangle(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3, const unsigned & y3,
		      const int & red, const int & green, const int & blue);
  void filledtriangle(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3, const unsigned & y3,
		      const Byte & red, const Byte & green, const Byte & blue);
  void filledtriangle(const unsigned & x1, const unsigned & y1,
		      const unsigned & x2, const unsigned & y2,
		      const unsigned & x3, const unsigned & y3,
		      const double & red, const double & green,
		      const double & blue);

  /* Filled Triangle, Blended
   * Draws the triangle specified by the three pairs of points in the
   * colour specified by the colour coefficients, and blended with
   * the background. See the description for Blended Functions.  The
   * colour components are either doubles from 0.0 to 1.0 or ints
   * from 0 to 65535.
   */
  void filledtriangle_blend(const unsigned & x1,const unsigned & y1,
			    const unsigned & x2, const unsigned & y2,
			    const unsigned & x3, const unsigned & y3,
			    const double & opacity, const int & red,
			    const int & green, const int & blue);
  void filledtriangle_blend(const unsigned & x1, const unsigned & y1,
			    const unsigned & x2, const unsigned & y2,
			    const unsigned & x3, const unsigned & y3,
			    const double & opacity, const Byte & red,
			    const Byte & green, const Byte & blue);
  void filledtriangle_blend(const unsigned & x1, const unsigned & y1,
			    const unsigned & x2, const unsigned & y2,
			    const unsigned & x3, const unsigned & y3,
			    const double & opacity, const double & red,
			    const double & green, const double & blue);

  /* Arrow,  Filled Arrow
   * Plots an arrow from (x1, y1) to (x2, y2) with the arrowhead at
   * the second point, given the size in pixels and the angle in
   * radians of the arrowhead. The plotted arrow consists of one main
   * line, and two smaller lines originating from the second
   * point. Filled Arrow plots the same, but the arrowhead is a solid
   * triangle.
   *
   * Tip: An angle of 10 to 30 degrees looks OK.
   */
   
  void arrow( const unsigned & x1, const unsigned & y1,
	      const unsigned & x2, const unsigned & y2,
	      const unsigned & size, const double & head_angle,
	      const double & red, const double & green, const double & blue);
  void arrow( const unsigned & x1, const unsigned & y1,
	      const unsigned & x2, const unsigned & y2,
	      const unsigned & size, const double & head_angle,
	      const Byte & red, const Byte & green, const Byte & blue);
  void arrow( const unsigned & x1, const unsigned & y1,
	      const unsigned & x2, const unsigned & y2,
	      const unsigned & size, const double & head_angle,
	      const int & red, const int & green, const int & blue);
   
  void filledarrow( const unsigned & x1, const unsigned & y1,
		    const unsigned & x2, const unsigned & y2,
		    const unsigned & size, const double & head_angle,
		    const double & red, const double & green,
		    const double & blue);
  void filledarrow( const unsigned & x1, const unsigned & y1,
		    const unsigned & x2, const unsigned & y2,
		    const unsigned & size, const double & head_angle,
		    const Byte & red, const Byte & green, const Byte & blue);
  void filledarrow( const unsigned & x1, const unsigned & y1,
		    const unsigned & x2, const unsigned & y2,
		    const unsigned & size, const double & head_angle,
		    const int & red, const int & green, const int & blue);

  /* Cross, Maltese Cross
   * Plots a simple cross at x, y, with the specified height and
   * width, and in the specified colour.  Maltese cross plots a
   * cross, as before, but adds bars at the end of each arm of the
   * cross.  The size of these bars is specified with x_bar_height
   * and y_bar_width.  The cross will look something like this:
   * 
   *    -----  <-- ( y_bar_width)
   *      |
   *      |
   *  |-------|  <-- ( x_bar_height )
   *      |
   *      |
   *    -----
   */
   
  void cross( const unsigned & x, const unsigned & y,
	      const unsigned & xwidth, const unsigned & yheight,
	      const double & red, const double & green, const double & blue);
  void cross( const unsigned & x, const unsigned & y,
	      const unsigned & xwidth, const unsigned & yheight,
	      const Byte & red, const Byte & green, const Byte & blue);
  void cross( const unsigned & x, const unsigned & y,
	      const unsigned & xwidth, const unsigned & yheight,
	      const int & red, const int & green, const int & blue);

  void maltesecross(const unsigned & x, const unsigned & y,
		    const unsigned & xwidth, const unsigned & yheight,
		    const unsigned & x_bar_height, const unsigned & y_bar_width,
		    const double & red, const double & green,
		    const double & blue);
  void maltesecross(const unsigned & x, const unsigned & y,
		    const unsigned & xwidth, const unsigned & yheight,
		    const unsigned & x_bar_height, const unsigned & y_bar_width,
		    const Byte & red, const Byte & green, const Byte & blue);
  void maltesecross(const unsigned & x, const unsigned & y,
		    const unsigned & xwidth, const unsigned & yheight,
		    const unsigned & x_bar_height, const unsigned & y_bar_width,
		    const int & red, const int & green, const int & blue);

  /* Diamond and filled diamond
   * Plots a diamond shape, given the x, y position, the width and
   * height, and the colour.  Filled diamond plots a filled
   * diamond.
   */
   
  void filleddiamond( const unsigned & x, const unsigned & y,
		      const int & width, const int & height,
		      const int & red, const int & green, const int & blue);
  void diamond( const unsigned & x, const unsigned & y,
		const int & width, const int & height,
		const int & red, const int & green, const int & blue);
   
  void filleddiamond( const unsigned & x, const unsigned & y,
		      const int & width, const int & height,
		      const double & red, const double & green,
		      const double & blue);
  void diamond( const unsigned & x, const unsigned & y,
		const int & width, const int & height,
		const double & red, const double & green, const double & blue);
   
  void filleddiamond( const unsigned & x, const unsigned & y,
		      const int & width, const int & height,
		      const Byte & red, const Byte & green, const Byte & blue);
  void diamond( const unsigned & x, const unsigned & y,
		const int & width, const int & height,
		const Byte & red, const Byte & green, const Byte & blue);

  /* Get Text Width, Get Text Width UTF8
   * Returns the approximate width, in pixels, of the specified
   * *unrotated* text. It is calculated by adding each letter's width
   * and kerning value (as specified in the TTF file). Note that this
   * will not give the position of the farthest pixel, but it will
   * give a pretty good idea of what area the text will occupy. Tip:
   * The text, when plotted unrotated, will fit approximately in a
   * box with its lower left corner at (x_start, y_start) and upper
   * right at (x_start + width, y_start + size), where width is given
   * by get_text_width() and size is the specified size of the text
   * to be plotted. Tip: Text plotted at position (x_start, y_start),
   * rotated with a given 'angle', and of a given 'size' whose width
   * is 'width', will fit approximately inside a rectangle whose
   * corners are at
   *     1  (x_start, y_start)
   *     2  (x_start + width*cos(angle), y_start + width*sin(angle))
   *     3  (x_start + width*cos(angle) - size*sin(angle), y_start + width*sin(angle) + size*cos(angle))
   *     4  (x_start - size*sin(angle), y_start + size*cos(angle))  
   */
   
  int get_text_width(char * face_path, const int & fontsize,  char * text);

  int get_text_width_utf8(char * face_path, const int & fontsize, char * text);
};

#endif

